home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / OGRID110 / GLPARSER.PAS < prev    next >
Pascal/Delphi Source File  |  1995-06-01  |  20KB  |  736 lines

  1. {*****************************************************************************
  2.  
  3.   OOGrid Library(TM) for Borland/Turbo Pascal (Real Mode/TV)
  4.   Copyright (C) 1994, 1995 by Arturo J. Monge
  5.   Portions Copyright (C) 1989,1990 Borland International, Inc.
  6.  
  7.   Borland's parser unit:
  8.     This is Borland's TCPARSER.PAS unit with some minor
  9.     modifications necessary for adapting TParserObject for
  10.     use by the TSpreadSheet object.
  11.  
  12.   Copyright (C) 1989,1990 Borland International, Inc.
  13.  
  14.   Last Modification : December 29th, 1994
  15.  
  16. *****************************************************************************}
  17.  
  18. {$O+,F+,N+,E+,X+}
  19.  
  20. unit GLParser;
  21.  
  22. {****************************************************************************}
  23.                                  interface
  24. {****************************************************************************}
  25.  
  26. uses Objects, GLCell, GLSupprt;
  27.  
  28. const
  29.   ParserStackSize = 10;
  30.   MaxFuncNameLen = 5;
  31.   TotalErrors = 7;
  32.   ExpLimit = 11356;
  33.   SqrLimit = 1E2466;
  34.   MaxExpLen = 4;
  35.   ErrParserStack = 1;
  36.   ErrBadRange = 2;
  37.   ErrExpression = 3;
  38.   ErrOperator = 4;
  39.   ErrOpenParen = 5;
  40.   ErrCell = 6;
  41.   ErrOpCloseParen = 7;
  42.  
  43. type
  44.   ErrorRange = 0..TotalErrors;
  45.  
  46.   TokenTypes = (Plus, Minus, Times, Divide, Expo, Colon, OParen, CParen,
  47.                 Num, CellT, Func, EOL, Bad, ERR);
  48.  
  49.   TokenRec = record
  50.     State : Byte;
  51.     case Byte of
  52.       0 : (Value : Extended);
  53.       1 : (CP : CellPos);
  54.       2 : (FuncName : String[MaxFuncNameLen]);
  55.   end;
  56.  
  57.   PParserObject = ^TParserObject;
  58.   TParserObject = object(TObject)
  59.        Inp : PString;
  60.        ParserHash : PCellHashTable;
  61.        PMaxCols : Word;
  62.        PMaxRows : Word;
  63.        Position : Word;
  64.        CurrToken : TokenRec;
  65.        StackTop : 0..ParserStackSize;
  66.        TokenError : ErrorRange;
  67.        ParseError : Boolean;
  68.        CType : CellTypes;
  69.        ParseValue : Extended;
  70.        Stack : array[1..ParserStackSize] of TokenRec;
  71.        TokenType : TokenTypes;
  72.        TokenLen : Word;
  73.        MathError, IsFormula : Boolean;
  74.     constructor Init(InitHash : PCellHashTable; InitInp : PString;
  75.                      InitPMaxCols, InitPMaxRows : Word);
  76.     function IsFunc(S : String) : Boolean;
  77.     procedure Push(Token : TokenRec);
  78.     procedure Pop(var Token : TokenRec);
  79.     function GotoState(Production : Word) : Word;
  80.     procedure Shift(State : Word);
  81.     procedure Reduce(Reduction : Word);
  82.     function NextToken : TokenTypes;
  83.     procedure Parse;
  84.     function CellValue(P : CellPos) : Extended;
  85.   end;
  86.  
  87. var
  88.    StandardParser : PParserObject;
  89.  
  90. {****************************************************************************}
  91.                                implementation
  92. {****************************************************************************}
  93.  
  94. uses TCUtil, MsgBox;
  95.  
  96. {** TParserObject ** }
  97.  
  98. constructor TParserObject.Init(InitHash : PCellHashTable;
  99.                            InitInp : PString;
  100.                            InitPMaxCols, InitPMaxRows : Word);
  101. { Initializes the parser }
  102. begin
  103.   ParserHash := InitHash;
  104.   Inp := InitInp;
  105.   PMaxCols := InitPMaxCols;
  106.   PMaxRows := InitPMaxRows;
  107.   Position := 1;
  108.   StackTop := 0;
  109.   TokenError := 0;
  110.   MathError := False;
  111.   IsFormula := False;
  112.   ParseError := False;
  113. end; { TParserObject.Init }
  114.  
  115. function TParserObject.IsFunc(S : String) : Boolean;
  116. { Checks to see if the parser is about to read a function }
  117. var
  118.   Counter, SLen : Word;
  119. begin
  120.    SLen := Length(S);
  121.    for Counter := 1 to SLen do
  122.    begin
  123.      if UpCase(Inp^[Pred(Position + Counter)]) <> S[Counter] then
  124.      begin
  125.        IsFunc := False;
  126.        Exit;
  127.      end;
  128.    end;
  129.    CurrToken.FuncName := UpperCase(Copy(Inp^, Position, SLen));
  130.    Inc(Position, SLen);
  131.    IsFunc := True;
  132. end; { IsFunc }
  133.  
  134. function TParserObject.NextToken : TokenTypes;
  135. { Gets the next Token from the Input stream }
  136. var
  137.   NumString : String[80];
  138.   FormLen, Place, TLen, NumLen, Check : Word;
  139.   Ch, FirstChar : Char;
  140.   Decimal : Boolean;
  141. begin
  142.    while (Position <= Length(Inp^)) and (Inp^[Position] = ' ') do
  143.      Inc(Position);
  144.    TokenLen := Position;
  145.    if Position > Length(Inp^) then
  146.    begin
  147.      NextToken := EOL;
  148.      TokenLen := 0;
  149.      Exit;
  150.    end;
  151.    Ch := UpCase(Inp^[Position]);
  152.    if Ch in ['!'] then
  153.    begin
  154.       NextToken := ERR;
  155.       IsFormula := True;
  156.       TokenLen := 0;
  157.       Exit;
  158.    end;
  159.    if Ch in ['0'..'9', '.'] then
  160.    begin
  161.      NumString := '';
  162.      TLen := Position;
  163.      Decimal := False;
  164.      while (TLen <= Length(Inp^)) and
  165.            ((Inp^[TLen] in ['0'..'9']) or
  166.             ((Inp^[TLen] = '.') and (not Decimal))) do
  167.      begin
  168.        NumString := NumString + Inp^[TLen];
  169.        if Ch = '.' then
  170.          Decimal := True;
  171.        Inc(TLen);
  172.      end;
  173.      if (TLen = 2) and (Ch = '.') then
  174.      begin
  175.        NextToken := BAD;
  176.        TokenLen := 0;
  177.        Exit;
  178.      end;
  179.      if (TLen <= Length(Inp^)) and ((Inp^[TLen] = 'E') or
  180.                               (Inp^[TLen] = 'e')) then
  181.      begin
  182.        NumString := NumString + 'E';
  183.        Inc(TLen);
  184.        if Inp^[TLen] in ['+', '-'] then
  185.        begin
  186.          NumString := NumString + Inp^[TLen];
  187.          Inc(TLen);
  188.        end;
  189.        NumLen := 1;
  190.        while (TLen <= Length(Inp^)) and (Inp^[TLen] in ['0'..'9']) and
  191.              (NumLen <= MaxExpLen) do
  192.        begin
  193.          NumString := NumString + Inp^[TLen];
  194.          Inc(NumLen);
  195.          Inc(TLen);
  196.        end;
  197.      end;
  198.      if NumString[1] = '.' then
  199.        NumString := '0' + NumString;
  200.      Val(NumString, CurrToken.Value, Check);
  201.      if Check <> 0 then
  202.        MathError := True;
  203.      NextToken := NUM;
  204.      Inc(Position, System.Length(NumString));
  205.      TokenLen := Position - TokenLen;
  206.      Exit;
  207.    end
  208.    else if Ch in Letters then
  209.    begin
  210.      if IsFunc('ABS') or
  211.         IsFunc('ATAN') or
  212.         IsFunc('COS') or
  213.         IsFunc('EXP') or
  214.         IsFunc('LN') or
  215.         IsFunc('ROUND') or
  216.         IsFunc('SIN') or
  217.         IsFunc('SQRT') or
  218.         IsFunc('SQR') or
  219.         IsFunc('TRUNC') then
  220.      begin
  221.        NextToken := FUNC;
  222.        TokenLen := Position - TokenLen;
  223.        Exit;
  224.      end;
  225.      if FormulaStart(Inp^, Position, PMaxCols, PMaxRows, CurrToken.CP,
  226.                      FormLen) then
  227.      begin
  228.        Inc(Position, FormLen);
  229.        IsFormula := True;
  230.        NextToken := CELLT;
  231.        TokenLen := Position - TokenLen;
  232.        Exit;
  233.      end
  234.      else begin
  235.        NextToken := BAD;
  236.        TokenLen := 0;
  237.        Exit;
  238.      end;
  239.    end
  240.    else begin
  241.      case Ch of
  242.        '+' : NextToken := PLUS;
  243.        '-' : NextToken := MINUS;
  244.        '*' : NextToken := TIMES;
  245.        '/' : NextToken := DIVIDE;
  246.        '^' : NextToken := EXPO;
  247.        ':' : NextToken := COLON;
  248.        '(' : NextToken := OPAREN;
  249.        ')' : NextToken := CPAREN;
  250.        else begin
  251.          NextToken := BAD;
  252.          TokenLen := 0;
  253.          Exit;
  254.        end;
  255.      end;
  256.      Inc(Position);
  257.      TokenLen := Position - TokenLen;
  258.      Exit;
  259.    end; { case }
  260. end; { TParserObject.NextToken }
  261.  
  262. procedure TParserObject.Push(Token : TokenRec);
  263. { Pushes a new Token onto the stack }
  264. begin
  265.   if StackTop = ParserStackSize then
  266.     TokenError := ErrParserStack
  267.   else begin
  268.     Inc(StackTop);
  269.     Stack[StackTop] := Token;
  270.   end;
  271. end; { TParserObject.Push }
  272.  
  273. procedure TParserObject.Pop(var Token : TokenRec);
  274. { Pops the top Token off of the stack }
  275. begin
  276.   Token := Stack[StackTop];
  277.   Dec(StackTop);
  278. end; { TParserObject.Pop }
  279.  
  280. function TParserObject.GotoState(Production : Word) : Word;
  281. { Finds the new state based on the just-completed production and the
  282.    top state.
  283. }
  284. var
  285.   State : Word;
  286. begin
  287.   State := Stack[StackTop].State;
  288.   if (Production <= 3) then
  289.   begin
  290.     case State of
  291.       0 : GotoState := 1;
  292.       9 : GotoState := 19;
  293.       20 : GotoState := 28;
  294.     end; { case }
  295.   end
  296.   else if Production <= 6 then
  297.   begin
  298.     case State of
  299.       0, 9, 20 : GotoState := 2;
  300.       12 : GotoState := 21;
  301.       13 : GotoState := 22;
  302.     end; { case }
  303.   end
  304.   else if Production <= 8 then
  305.   begin
  306.     case State of
  307.       0, 9, 12, 13, 20 : GotoState := 3;
  308.       14 : GotoState := 23;
  309.       15 : GotoState := 24;
  310.       16 : GotoState := 25;
  311.     end; { case }
  312.   end
  313.   else if Production <= 10 then
  314.   begin
  315.     case State of
  316.       0, 9, 12..16, 20 : GotoState := 4;
  317.     end; { case }
  318.   end
  319.   else if Production <= 12 then
  320.   begin
  321.     case State of
  322.       0, 9, 12..16, 20 : GotoState := 6;
  323.       5 : GotoState := 17;
  324.     end; { case }
  325.   end
  326.   else begin
  327.     case State of
  328.       0, 5, 9, 12..16, 20 : GotoState := 8;
  329.     end; { case }
  330.   end;
  331. end; { TParserObject.GotoState }
  332.  
  333. function TParserObject.CellValue(P : CellPos) : Extended;
  334. { Returns the value of a cell }
  335. var
  336.   CPtr : PCell;
  337. begin
  338.   CPtr := ParserHash^.Search(P);
  339.   with CPtr^ do
  340.   begin
  341.     if (not LegalValue) or HasError then
  342.     begin
  343.       MathError := True;
  344.       CellValue := 0;
  345.     end
  346.     else
  347.       CellValue := CurrValue;
  348.   end; { with }
  349. end; { TParserObject.CellValue }
  350.  
  351. procedure TParserObject.Shift(State : Word);
  352. { Shifts a Token onto the stack }
  353. begin
  354.   CurrToken.State := State;
  355.   Push(CurrToken);
  356.   TokenType := NextToken;
  357. end; { TParserObject.Shift }
  358.  
  359. procedure TParserObject.Reduce(Reduction : Word);
  360. { Completes a reduction }
  361. var
  362.   Token1, Token2 : TokenRec;
  363.   Counter : CellPos;
  364. begin
  365.   case Reduction of
  366.     1 : begin
  367.       Pop(Token1);
  368.       Pop(Token2);
  369.       Pop(Token2);
  370.       CurrToken.Value := Token1.Value + Token2.Value;
  371.     end;
  372.     2 : begin
  373.       Pop(Token1);
  374.       Pop(Token2);
  375.       Pop(Token2);
  376.       CurrToken.Value := Token2.Value - Token1.Value;
  377.     end;
  378.     4 : begin
  379.       Pop(Token1);
  380.       Pop(Token2);
  381.       Pop(Token2);
  382.       CurrToken.Value := Token1.Value * Token2.Value;
  383.     end;
  384.     5 : begin
  385.       Pop(Token1);
  386.       Pop(Token2);
  387.       Pop(Token2);
  388.       if Token1.Value = 0 then
  389.         MathError := True
  390.       else
  391.         CurrToken.Value := Token2.Value / Token1.Value;
  392.     end;
  393.     7 : begin
  394.       Pop(Token1);
  395.       Pop(Token2);
  396.       Pop(Token2);
  397.       if Token2.Value <= 0 then
  398.         MathError := True
  399.       else if (Token1.Value * Ln(Token2.Value) < -ExpLimit) or
  400.               (Token1.Value * Ln(Token2.Value) > ExpLimit) then
  401.         MathError := True
  402.       else
  403.         CurrToken.Value := Exp(Token1.Value * Ln(Token2.Value));
  404.     end;
  405.     9 : begin
  406.       Pop(Token1);
  407.       Pop(Token2);
  408.       CurrToken.Value := -Token1.Value;
  409.     end;
  410.     11 : begin
  411.       Pop(Token1);
  412.       Pop(Token2);
  413.       Pop(Token2);
  414.       CurrToken.Value := 0;
  415.       if Token1.CP.Row = Token2.CP.Row then
  416.       begin
  417.         if Token1.CP.Col < Token2.CP.Col then
  418.           TokenError := ErrBadRange
  419.         else begin
  420.           Counter.Row := Token1.CP.Row;
  421.           for Counter.Col := Token2.CP.Col to Token1.CP.Col do
  422.             CurrToken.Value := CurrToken.Value + CellValue(Counter);
  423.         end;
  424.       end
  425.       else if Token1.CP.Col = Token2.CP.Col then
  426.       begin
  427.         if Token1.CP.Row < Token2.CP.Row then
  428.           TokenError := ErrBadRange
  429.         else begin
  430.           Counter.Col := Token1.CP.Col;
  431.           for Counter.Row := Token2.CP.Row to Token1.CP.Row do
  432.             CurrToken.Value := CurrToken.Value + CellValue(Counter);
  433.         end;
  434.       end
  435.       else if (Token1.CP.Col >= Token2.CP.Col) and
  436.               (Token1.CP.Row >= Token2.CP.Row) then
  437.       begin
  438.         for Counter.Row := Token2.CP.Row to Token1.CP.Row do
  439.         begin
  440.           for Counter.Col := Token2.CP.Col to Token1.CP.Col do
  441.             CurrToken.Value := CurrToken.Value + CellValue(Counter);
  442.         end;
  443.       end
  444.       else
  445.         TokenError := ErrBadRange;
  446.     end;
  447.     13 : begin
  448.       Pop(CurrToken);
  449.       CurrToken.Value := CellValue(CurrToken.CP);
  450.     end;
  451.     14 : begin
  452.       Pop(Token1);
  453.       Pop(CurrToken);
  454.       Pop(Token1);
  455.     end;
  456.     16 : begin
  457.       Pop(Token1);
  458.       Pop(CurrToken);
  459.       Pop(Token1);
  460.       Pop(Token1);
  461.       if Token1.FuncName = 'ABS' then
  462.         CurrToken.Value := Abs(CurrToken.Value)
  463.       else if Token1.FuncName = 'ATAN' then
  464.         CurrToken.Value := ArcTan(CurrToken.Value)
  465.       else if Token1.FuncName = 'COS' then
  466.       begin
  467.          if (CurrToken.Value < -9E18) or (CurrToken.Value > 9E18) then
  468.             MathError := True
  469.          else
  470.             CurrToken.Value := Cos(CurrToken.Value)
  471.       end {...if Token1.FuncName = 'SIN' }
  472.       else if Token1.FuncName = 'EXP' then
  473.       begin
  474.         if (CurrToken.Value < -ExpLimit) or (CurrToken.Value > ExpLimit) then
  475.           MathError := True
  476.         else
  477.           CurrToken.Value := Exp(CurrToken.Value);
  478.       end
  479.       else if Token1.FuncName = 'LN' then
  480.       begin
  481.         if CurrToken.Value <= 0 then
  482.           MathError := True
  483.         else
  484.           CurrToken.Value := Ln(CurrToken.Value);
  485.       end
  486.       else if Token1.FuncName = 'ROUND' then
  487.       begin
  488.         if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then
  489.           MathError := True
  490.         else
  491.           CurrToken.Value := Round(CurrToken.Value);
  492.       end
  493.       else if Token1.FuncName = 'SIN' then
  494.       begin
  495.          if (CurrToken.Value < -9E18) or (CurrToken.Value > 9E18) then
  496.             MathError := True
  497.          else
  498.             CurrToken.Value := Sin(CurrToken.Value)
  499.       end {...if Token1.FuncName = 'SIN' }
  500.       else if Token1.FuncName = 'SQRT' then
  501.       begin
  502.         if CurrToken.Value < 0 then
  503.           MathError := True
  504.         else
  505.           CurrToken.Value := Sqrt(CurrToken.Value);
  506.       end
  507.       else if Token1.FuncName = 'SQR' then
  508.       begin
  509.         if (CurrToken.Value < -SQRLIMIT) or (CurrToken.Value > SQRLIMIT) then
  510.           MathError := True
  511.         else
  512.           CurrToken.Value := Sqr(CurrToken.Value);
  513.       end
  514.       else if Token1.FuncName = 'TRUNC' then
  515.       begin
  516.         if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then
  517.           MathError := True
  518.         else
  519.           CurrToken.Value := Trunc(CurrToken.Value);
  520.       end;
  521.     end;
  522.     3, 6, 8, 10, 12, 15 : Pop(CurrToken);
  523.   end; { case }
  524.   CurrToken.State := GotoState(Reduction);
  525.   Push(CurrToken);
  526. end; { TParserObject.Reduce }
  527.  
  528. procedure TParserObject.Parse;
  529. { Parses an input stream }
  530. var
  531.   FirstToken : TokenRec;
  532.   Accepted : Boolean;
  533. begin
  534.   Position := 1;
  535.   StackTop := 0;
  536.   TokenError := 0;
  537.   MathError := False;
  538.   IsFormula := False;
  539.   ParseError := False;
  540.   begin
  541.     if (Length(Inp^) = 2) and (Inp^[1] = RepeatFirstChar) then
  542.     begin
  543.       CType := ClRepeat;
  544.       Exit;
  545.     end;
  546.     if Inp^[1] = TextFirstChar then
  547.     begin
  548.       CType := ClText;
  549.       Exit;
  550.     end;
  551.   end; { with }
  552.   Accepted := False;
  553.   FirstToken.State := 0;
  554.   FirstToken.Value := 0;
  555.   Push(FirstToken);
  556.   TokenType := NextToken;
  557.   repeat
  558.     case Stack[StackTop].State of
  559.       0, 9, 12..16, 20 : begin
  560.         if TokenType = NUM then
  561.           Shift(10)
  562.         else if TokenType = CELLT then
  563.           Shift(7)
  564.         else if TokenType = FUNC then
  565.           Shift(11)
  566.         else if TokenType = MINUS then
  567.           Shift(5)
  568.         else if TokenType = OPAREN then
  569.           Shift(9)
  570.         else if TokenType = ERR then
  571.           begin
  572.              MathError := True;
  573.              Accepted := True;
  574.           end
  575.         else begin
  576.           TokenError := ErrExpression;
  577.           Dec(Position, TokenLen);
  578.         end;
  579.       end;
  580.       1 : begin
  581.         if TokenType = EOL then
  582.           Accepted := True
  583.         else if TokenType = PLUS then
  584.           Shift(12)
  585.         else if TokenType = MINUS then
  586.           Shift(13)
  587.         else begin
  588.           TokenError := ErrOperator;
  589.           Dec(Position, TokenLen);
  590.         end;
  591.       end;
  592.       2 : begin
  593.         if TokenType = TIMES then
  594.           Shift(14)
  595.         else if TokenType = DIVIDE then
  596.           Shift(15)
  597.         else
  598.           Reduce(3);
  599.       end;
  600.       3 : Reduce(6);
  601.       4 : begin
  602.        if TokenType = EXPO then
  603.          Shift(16)
  604.        else
  605.          Reduce(8);
  606.       end;
  607.       5 : begin
  608.         if TokenType = NUM then
  609.           Shift(10)
  610.         else if TokenType = CELLT then
  611.           Shift(7)
  612.         else if TokenType = FUNC then
  613.           Shift(11)
  614.         else if TokenType = OPAREN then
  615.           Shift(9)
  616.         else
  617.           TokenError := ErrExpression;
  618.       end;
  619.       6 : Reduce(10);
  620.       7 : begin
  621.         if TokenType = COLON then
  622.           Shift(18)
  623.         else
  624.           Reduce(13);
  625.       end;
  626.       8 : Reduce(12);
  627.       10 : Reduce(15);
  628.       11 : begin
  629.         if TokenType = OPAREN then
  630.           Shift(20)
  631.         else
  632.           TokenError := ErrOpenParen;
  633.       end;
  634.       17 : Reduce(9);
  635.       18 : begin
  636.         if TokenType = CELLT then
  637.           Shift(26)
  638.         else
  639.           TokenError := ErrCell;
  640.       end;
  641.       19 : begin
  642.         if TokenType = PLUS then
  643.           Shift(12)
  644.         else if TokenType = MINUS then
  645.           Shift(13)
  646.         else if TokenType = CPAREN then
  647.           Shift(27)
  648.         else
  649.           TokenError := ErrOpCloseParen;
  650.       end;
  651.       21 : begin
  652.         if TokenType = TIMES then
  653.           Shift(14)
  654.         else if TokenType = DIVIDE then
  655.           Shift(15)
  656.         else
  657.           Reduce(1);
  658.       end;
  659.       22 : begin
  660.         if TokenType = TIMES then
  661.           Shift(14)
  662.         else if TokenType = DIVIDE then
  663.           Shift(15)
  664.         else
  665.           Reduce(2);
  666.       end;
  667.       23 : Reduce(4);
  668.       24 : Reduce(5);
  669.       25 : Reduce(7);
  670.       26 : Reduce(11);
  671.       27 : Reduce(14);
  672.       28 : begin
  673.         if TokenType = PLUS then
  674.           Shift(12)
  675.         else if TokenType = MINUS then
  676.           Shift(13)
  677.         else if TokenType = CPAREN then
  678.           Shift(29)
  679.         else
  680.           TokenError := ErrOpCloseParen;
  681.       end;
  682.       29 : Reduce(16);
  683.     end; { case }
  684.   until Accepted or (TokenError <> 0);
  685.   if TokenError <> 0 then
  686.   begin
  687.       if TokenError = ErrBadRange then
  688.         Dec(Position, TokenLen);
  689.       case TokenError of
  690.          1 : MessageBox(GLStringList^.Get(sParseError1), NIL,
  691.                mfError + mfCancelButton);
  692.          2 : MessageBox(GLStringList^.Get(sParseError2), NIL,
  693.                mfError + mfCancelButton);
  694.          3 : MessageBox(GLStringList^.Get(sParseError3), NIL,
  695.                mfError + mfCancelButton);
  696.          4 : MessageBox(GLStringList^.Get(sParseError4), NIL,
  697.                mfError + mfCancelButton);
  698.          5 : MessageBox(GLStringList^.Get(sParseError5), NIL,
  699.                mfError + mfCancelButton);
  700.          6 : MessageBox(GLStringList^.Get(sParseError6), NIL,
  701.                mfError + mfCancelButton);
  702.          7 : MessageBox(GLStringList^.Get(sParseError7), NIL,
  703.                mfError + mfCancelButton);
  704.       end;
  705.       Exit;
  706.   end;
  707.   if IsFormula then
  708.     CType := ClFormula
  709.   else
  710.     CType := ClValue;
  711.   if MathError then
  712.   begin
  713.     ParseError := True;
  714.     ParseValue := 0;
  715.     Exit;
  716.   end;
  717.   ParseError := False;
  718.   ParseValue := Stack[StackTop].Value;
  719. end; { TParserObject.Parse }
  720.  
  721. {** Exit procedure **}
  722.  
  723. var
  724.   SavedExitProc : Pointer;
  725.  
  726. procedure GLParserExit; far;
  727. begin
  728.   Dispose(StandardParser, Done);
  729.   ExitProc := SavedExitProc;
  730. end; {...GLParserExit }
  731.  
  732. begin
  733.   SavedExitProc := ExitProc;
  734.   ExitProc := @GLParserExit;
  735.   New(StandardParser, Init(NIL, NIL, 0, 0));
  736. end. {...TSParser unit }